﻿using System;
using System.CodeDom.Compiler;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows.Forms;
using Microsoft.CSharp;
using RegexSharp.Core;

namespace RegexSharp
{
    public partial class Form_Main : Form
    {
        private Core.RegexEngine _regexEngine = new Core.RegexEngine();
        private Thread _runThread;

        private int _maxDisplayedMatchResults = Config.Global.MaxDisplayedItemsInList;

        private DataTable _performanceList = new DataTable("PerformanceList");
        private int _performanceRerunTimes;

        private ToolStripMenuItem _customSnippetsMenuItem;

        private string _currentGenerateCodeType;
        private string _currentGenerateCode;

        public Form_Main()
        {
            AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

            InitializeComponent();

            SetUI();
            LoadSnippets();
            CreatePerformanceList();
        }

        private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            Form_Error form_Error = new Form_Error();
            form_Error.RunMode = GetCurrentRunMode().ToString();
            form_Error.Content = rsRichTextBox_Content.Text;
            form_Error.RegexText = rsRichTextBox_Regex.Text;
            form_Error.Replacement = rsRichTextBox_Replace_Replacement.Text;
            form_Error.MatchEvaluator = rsRichTextBox_Replace_MatchEvaluator.Text;
            form_Error.UnhandledException = e.ExceptionObject as Exception;
            form_Error.ShowDialog(this);
        }

        private void SetUI()
        {
            dataGridView_Performance_Main.AutoGenerateColumns = false;
            tabControl_ModeTabs_SelectedIndexChanged(null, null);
            toolStripComboBox_Message_GenerateCodeType.SelectedIndex = 0;
            toolStripComboBox_Performance_RerunTimes.Text = "1000";
            toolStripStatusLabel_GetUpdate.Alignment = ToolStripItemAlignment.Right;

            SetFont();
        }

        private void SetFont()
        {
            Font textFont = new Font(Config.Global.TextFont, Config.Global.TextFontSize);

            rsRichTextBox_Content.Font = textFont;
            rsTreeView_Match_Result.Font = textFont;

            rsRichTextBox_Regex.Font = textFont;
            rsTextBox_Message.Font = textFont;

            rsRichTextBox_Replace_Result.Font = textFont;
            rsRichTextBox_Replace_Replacement.Font = textFont;

            rsTreeView_Split_Result.Font = textFont;
        }

        private void LoadSnippets()
        {
            if (toolStripSplitButton_RegexSnippets.DropDownItems.Contains(_customSnippetsMenuItem))
            {
                toolStripSplitButton_RegexSnippets.DropDownItems.Remove(_customSnippetsMenuItem);
            }

            // Custom Snippets
            Helper.Serializer<Core.Snippet> snippetSerializer = new Helper.Serializer<Core.Snippet>();

            if (snippetSerializer.CanDeserialize(Config.Global.CustomSnippetsFile))
            {
                Config.Global.CustomSnippets = snippetSerializer.Deserialize(Config.Global.CustomSnippetsFile);
                _customSnippetsMenuItem = CreateSnippetsMenu(Config.Global.CustomSnippets);
                toolStripSplitButton_RegexSnippets.DropDownItems.Add(_customSnippetsMenuItem);
            }
        }

        private ToolStripMenuItem CreateSnippetsMenu(Core.Snippet snippet)
        {
            ToolStripMenuItem snippetMenuItem = new ToolStripMenuItem();
            snippetMenuItem.Text = snippet.Name;
            snippetMenuItem.Tag = snippet.Value;
            snippetMenuItem.Click += new EventHandler(SnippetMenuItem_Click);

            for (int i = 0; i < snippet.Subs.Count; i++)
            {
                snippetMenuItem.DropDownItems.Add(CreateSnippetsMenu(snippet.Subs[i]));
            }

            return snippetMenuItem;
        }

        private void SnippetMenuItem_Click(object sender, EventArgs e)
        {
            if (rsRichTextBox_Regex.Focused)
            {
                ToolStripMenuItem snippetMenuItem = sender as ToolStripMenuItem;
                string str = snippetMenuItem.Tag as string;

                if (!string.IsNullOrEmpty(str))
                {
                    int index = rsRichTextBox_Regex.SelectionStart;
                    rsRichTextBox_Regex.SetText(rsRichTextBox_Regex.Text.Insert(rsRichTextBox_Regex.SelectionStart, str));
                    rsRichTextBox_Regex.SelectionStart = index + str.Length;

                    //Clipboard.SetText(str);
                    //rsRichTextBox_Regex.Paste();
                }
            }
        }

        private void CreatePerformanceList()
        {
            _performanceList.Columns.Add("Regex", typeof(string));
            _performanceList.Columns.Add("Options", typeof(RegexOptions));
            _performanceList.Columns.Add("ElapsedTime", typeof(TimeSpan));
            _performanceList.Columns.Add("RegexObj", typeof(Regex));

            dataGridView_Performance_Main.DataSource = _performanceList;
        }

        private string GetElapsedTime(Action action)
        {
            DateTime start = DateTime.Now;
            action.Invoke();
            TimeSpan elapsedTime = DateTime.Now - start;

            return elapsedTime.ToString();
        }

        // Run

        private RegexOptions GetRegexOptions()
        {
            RegexOptions options = RegexOptions.None;

            if (toolStripMenuItem_IgnoreCase.Checked)
                options |= RegexOptions.IgnoreCase;
            if (toolStripMenuItem_Multiline.Checked)
                options |= RegexOptions.Multiline;
            if (toolStripMenuItem_ExplicitCapture.Checked)
                options |= RegexOptions.ExplicitCapture;
            if (toolStripMenuItem_Compiled.Checked)
                options |= RegexOptions.Compiled;
            if (toolStripMenuItem_Singleline.Checked)
                options |= RegexOptions.Singleline;
            if (toolStripMenuItem_IgnorePatternWhitespace.Checked)
                options |= RegexOptions.IgnorePatternWhitespace;
            if (toolStripMenuItem_RightToLeft.Checked)
                options |= RegexOptions.RightToLeft;
            if (toolStripMenuItem_ECMAScript.Checked)
                options |= RegexOptions.ECMAScript;
            if (toolStripMenuItem_CultureInvariant.Checked)
                options |= RegexOptions.CultureInvariant;

            return options;
        }

        private void SetRegexOption(ToolStripMenuItem menuItem, RegexOptions trueFlag, RegexOptions options)
        {
            if (options.HasFlag(trueFlag))
            {
                menuItem.Checked = true;
            }
            else
            {
                menuItem.Checked = false;
            }
        }

        private void SetRegexOptions(RegexOptions options)
        {
            SetRegexOption(toolStripMenuItem_IgnoreCase, RegexOptions.IgnoreCase, options);
            SetRegexOption(toolStripMenuItem_Multiline, RegexOptions.Multiline, options);
            SetRegexOption(toolStripMenuItem_ExplicitCapture, RegexOptions.ExplicitCapture, options);
            SetRegexOption(toolStripMenuItem_Compiled, RegexOptions.Compiled, options);
            SetRegexOption(toolStripMenuItem_Singleline, RegexOptions.Singleline, options);
            SetRegexOption(toolStripMenuItem_IgnorePatternWhitespace, RegexOptions.IgnorePatternWhitespace, options);
            SetRegexOption(toolStripMenuItem_RightToLeft, RegexOptions.RightToLeft, options);
            SetRegexOption(toolStripMenuItem_ECMAScript, RegexOptions.ECMAScript, options);
            SetRegexOption(toolStripMenuItem_CultureInvariant, RegexOptions.CultureInvariant, options);
        }

        private string GetCreatedCode()
        {
            RegexOptions options = GetRegexOptions();
            StringBuilder optionsStr = new StringBuilder();
            bool hasflag = false;
            string OrOperator = string.Empty;

            switch (_currentGenerateCodeType)
            {
                case "C#":
                    OrOperator = " | ";
                    break;
                case "VB.Net":
                    OrOperator = " Or ";
                    break;
                default:
                    break;
            }

            if (options.HasFlag(RegexOptions.IgnoreCase))
            {
                optionsStr.Append("RegexOptions.IgnoreCase");
                optionsStr.Append(OrOperator);
                hasflag = true;
            }
            if (options.HasFlag(RegexOptions.Multiline))
            {
                optionsStr.Append("RegexOptions.Multiline");
                optionsStr.Append(OrOperator);
                hasflag = true;
            }
            if (options.HasFlag(RegexOptions.ExplicitCapture))
            {
                optionsStr.Append("RegexOptions.ExplicitCapture");
                optionsStr.Append(OrOperator);
                hasflag = true;
            }
            if (options.HasFlag(RegexOptions.Compiled))
            {
                optionsStr.Append("RegexOptions.Compiled");
                optionsStr.Append(OrOperator);
                hasflag = true;
            }
            if (options.HasFlag(RegexOptions.Singleline))
            {
                optionsStr.Append("RegexOptions.Singleline");
                optionsStr.Append(OrOperator);
                hasflag = true;
            }
            if (options.HasFlag(RegexOptions.IgnorePatternWhitespace))
            {
                optionsStr.Append("RegexOptions.IgnorePatternWhitespace");
                optionsStr.Append(OrOperator);
                hasflag = true;
            }
            if (options.HasFlag(RegexOptions.RightToLeft))
            {
                optionsStr.Append("RegexOptions.RightToLeft");
                optionsStr.Append(OrOperator);
                hasflag = true;
            }
            if (options.HasFlag(RegexOptions.ECMAScript))
            {
                optionsStr.Append("RegexOptions.ECMAScript");
                optionsStr.Append(OrOperator);
                hasflag = true;
            }
            if (options.HasFlag(RegexOptions.CultureInvariant))
            {
                optionsStr.Append("RegexOptions.CultureInvariant");
                optionsStr.Append(OrOperator);
                hasflag = true;
            }

            if (!hasflag)
            {
                optionsStr.Clear();
                optionsStr.Append("RegexOptions.None");
            }
            else
            {
                optionsStr.Remove(optionsStr.Length - OrOperator.Length, OrOperator.Length);
            }

            switch (_currentGenerateCodeType)
            {
                case "C#":
                    _currentGenerateCode = string.Format("using System.Text.RegularExpressions;\r\nRegex regex = new Regex(@\"{0}\", {1});", rsRichTextBox_Regex.Text.Replace("\"", "\"\""), optionsStr.ToString());
                    break;
                case "VB.Net":
                    _currentGenerateCode = string.Format("Imports System.Text.RegularExpressions\r\nDim regex As Regex = New Regex(\"{0}\", {1})", rsRichTextBox_Regex.Text.Replace("\"", "\"\""), optionsStr.ToString());
                    break;
            }

            return "\r\n" + _currentGenerateCodeType + " Code:\r\n" + _currentGenerateCode + "\r\n";
        }

        private MatchEvaluator GetMatchEvaluator()
        {
            StringBuilder sbCode = new StringBuilder();
            sbCode.Append("using System;");
            sbCode.AppendLine();
            sbCode.Append("using System.Text.RegularExpressions;");
            sbCode.AppendLine();
            sbCode.Append("namespace RSCodeGen");
            sbCode.AppendLine();
            sbCode.Append("{");
            sbCode.AppendLine();
            sbCode.Append("    public class RSMatchEvaluator");
            sbCode.AppendLine();
            sbCode.Append("    {");
            sbCode.AppendLine();
            sbCode.Append("        public MatchEvaluator GetMatchEvaluator()");
            sbCode.AppendLine();
            sbCode.Append("        {");
            sbCode.AppendLine();
            sbCode.Append("            return new MatchEvaluator((Match match) => {");
            sbCode.AppendLine();
            sbCode.Append("            ");
            sbCode.Append(rsRichTextBox_Replace_MatchEvaluator.Text);
            sbCode.AppendLine();
            sbCode.Append("            });");
            sbCode.AppendLine();
            sbCode.Append("        }");
            sbCode.AppendLine();
            sbCode.Append("    }");
            sbCode.AppendLine();
            sbCode.Append("}");

            CSharpCodeProvider csCodePrivoder = new CSharpCodeProvider();

            CompilerParameters compilerParameters = new CompilerParameters();
            compilerParameters.ReferencedAssemblies.Add("System.dll");
            compilerParameters.GenerateExecutable = false;
            compilerParameters.GenerateInMemory = true;

            CompilerResults compilerResults = csCodePrivoder.CompileAssemblyFromSource(compilerParameters, sbCode.ToString());

            if (compilerResults.Errors.HasErrors)
            {
                StringBuilder sbError = new StringBuilder();

                sbError.AppendLine("(MatchEvaluator compile)");
                foreach (CompilerError error in compilerResults.Errors)
                {
                    sbError.AppendLine(error.ErrorText);
                }

                throw new Exception(sbError.ToString());
            }
            else
            {
                Assembly getMatchEvaluatorAssembly = compilerResults.CompiledAssembly;
                object rsMatchEvaluator = getMatchEvaluatorAssembly.CreateInstance("RSCodeGen.RSMatchEvaluator");
                MethodInfo getMatchEvaluator = rsMatchEvaluator.GetType().GetMethod("GetMatchEvaluator");

                return getMatchEvaluator.Invoke(rsMatchEvaluator, null) as MatchEvaluator;
            }
        }

        private enum RunMode
        {
            Match,
            Replace_Replacement,
            Replace_MatchEvaluator,
            Split,
            Performance,
        }

        private RunMode GetCurrentRunMode()
        {
            switch (tabControl_Main.SelectedIndex)
            {
                case 0:
                    return RunMode.Match;
                case 1:
                    switch (tabControl_Replace.SelectedIndex)
                    {
                        case 0:
                            return RunMode.Replace_Replacement;
                        case 1:
                            return RunMode.Replace_MatchEvaluator;
                    }
                    break;
                case 2:
                    return RunMode.Split;
                case 3:
                    return RunMode.Performance;
            }

            return RunMode.Match;
        }

        private void Run(RunMode mode)
        {
            if (_runThread == null || _runThread.ThreadState != ThreadState.Running)
            {
                if (mode == RunMode.Match)
                {
                    _runThread = new Thread(new ParameterizedThreadStart(RunMatchMode));

                    try
                    {
                        _runThread.Start(new Core.RegexMatchInfo()
                        {
                            Content = rsRichTextBox_Content.Text,
                            Regex = new Regex(rsRichTextBox_Regex.Text, GetRegexOptions()),
                        });
                    }
                    catch (Exception e)
                    {
                        rsTreeView_Match_Result.ClearNodes();
                        rsTextBox_Message.SetText("Match failed.\r\nError:\r\n{0}", e.Message);
                        return;
                    }
                }
                else if (mode == RunMode.Replace_Replacement)
                {
                    _runThread = new Thread(new ParameterizedThreadStart(RunReplaceReplacementMode));

                    try
                    {
                        _runThread.Start(new Core.RegexReplaceReplacementInfo()
                        {
                            Content = rsRichTextBox_Content.Text,
                            Regex = new Regex(rsRichTextBox_Regex.Text, GetRegexOptions()),
                            Replacement = rsRichTextBox_Replace_Replacement.Text,
                        });
                    }
                    catch (Exception e)
                    {
                        rsRichTextBox_Replace_Result.SetText("");
                        rsTextBox_Message.SetText("Replace.Replacement failed.\r\nError:\r\n{0}", e.Message);
                        return;
                    }
                }
                else if (mode == RunMode.Replace_MatchEvaluator)
                {
                    _runThread = new Thread(new ParameterizedThreadStart(RunReplaceMatchEvaluatorMode));

                    try
                    {
                        _runThread.Start(new Core.RegexReplaceMatchEvaluatorInfo()
                        {
                            Content = rsRichTextBox_Content.Text,
                            Regex = new Regex(rsRichTextBox_Regex.Text, GetRegexOptions()),
                            MatchEvaluator = GetMatchEvaluator(),
                        });
                    }
                    catch (Exception e)
                    {
                        rsRichTextBox_Replace_Result.SetText("");
                        rsTextBox_Message.SetText("Replace.MatchEvaluator failed.\r\nError:\r\n{0}", e.Message);
                        return;
                    }
                }
                else if (mode == RunMode.Split)
                {
                    _runThread = new Thread(new ParameterizedThreadStart(RunSplitMode));

                    try
                    {
                        _runThread.Start(new Core.RegexSplitInfo()
                        {
                            Content = rsRichTextBox_Content.Text,
                            Regex = new Regex(rsRichTextBox_Regex.Text, GetRegexOptions()),
                        });
                    }
                    catch (Exception e)
                    {
                        rsTextBox_Message.SetText("Split failed.\r\nError:\r\n{0}", e.Message);
                        return;
                    }
                }
                else if (mode == RunMode.Performance)
                {
                    for (int i = 0; i < _performanceList.Rows.Count; i++)
                    {
                        _performanceList.Rows[i]["ElapsedTime"] = DBNull.Value;
                    }

                    _runThread = new Thread(new ParameterizedThreadStart(RunPerformanceMode));

                    try
                    {
                        _runThread.Start(new Core.RegexPerformanceInfo()
                        {
                            Content = rsRichTextBox_Content.Text,
                        });
                    }
                    catch (Exception e)
                    {
                        rsTextBox_Message.SetText("Performance failed.\r\nError:\r\n{0}", e.Message);
                        return;
                    }
                }
            }
        }

        private void RunMatchMode(object arg)
        {
            rsTextBox_Message.SetText("Running...");

            Core.RegexMatchInfo regexMatchInfo = arg as Core.RegexMatchInfo;
            rsTreeView_Match_Result.ClearNodes();

            TreeNode[] nodes = _regexEngine.Matches(regexMatchInfo.Content, regexMatchInfo.Regex);
            TreeNode[] displayedNodes = nodes.Take(_maxDisplayedMatchResults).ToArray();

            rsTreeView_Match_Result.AddNodes(displayedNodes.ToArray());

            if (displayedNodes.Count() < nodes.Count())
            {
                rsTextBox_Message.SetText("Match done. Found {0} result(s), but only top {1} results can be displayed.\r\n", nodes.Count(), displayedNodes.Count());
            }
            else
            {
                rsTextBox_Message.SetText("Match done. Found {0} result(s).\r\n", displayedNodes.Count());
            }

            rsTextBox_Message.SetAppendText(GetCreatedCode());
        }

        private void RunReplaceReplacementMode(object arg)
        {
            rsTextBox_Message.SetText("Running...");

            Core.RegexReplaceReplacementInfo regexReplaceReplacementInfo = arg as Core.RegexReplaceReplacementInfo;

            rsRichTextBox_Replace_Result.SetText(_regexEngine.Replace(regexReplaceReplacementInfo.Content, regexReplaceReplacementInfo.Regex, regexReplaceReplacementInfo.Replacement));
            rsTextBox_Message.SetText("Replace.Replacement done.\r\n");
            rsTextBox_Message.SetAppendText(GetCreatedCode());
        }

        private void RunReplaceMatchEvaluatorMode(object arg)
        {
            rsTextBox_Message.SetText("Running...");

            Core.RegexReplaceMatchEvaluatorInfo regexReplaceMatchEvaluatorInfo = arg as Core.RegexReplaceMatchEvaluatorInfo;

            try
            {
                rsRichTextBox_Replace_Result.SetText(_regexEngine.Replace(regexReplaceMatchEvaluatorInfo.Content, regexReplaceMatchEvaluatorInfo.Regex, regexReplaceMatchEvaluatorInfo.MatchEvaluator));
                rsTextBox_Message.SetText("Replace.MatchEvaluator done.\r\n");
                rsTextBox_Message.SetAppendText(GetCreatedCode());
            }
            catch (Exception e)
            {
                rsTextBox_Message.SetText("Replace.MatchEvaluator failed.\r\nError:\r\n{0}\r\n(This error may be caused by your MatchEvaluator code)", e.Message);
            }
        }

        private void RunSplitMode(object arg)
        {
            rsTextBox_Message.SetText("Running...");

            Core.RegexSplitInfo regexSplitInfo = arg as Core.RegexSplitInfo;

            rsTreeView_Split_Result.ClearNodes();

            TreeNode[] nodes = _regexEngine.Split(regexSplitInfo.Content, regexSplitInfo.Regex);
            TreeNode[] displayedNodes = nodes.Take(_maxDisplayedMatchResults).ToArray();

            rsTreeView_Split_Result.AddNodes(displayedNodes.ToArray());

            if (displayedNodes.Count() < nodes.Count())
            {
                rsTextBox_Message.SetText("Split done. Found {0} result(s), but only top {1} results can be displayed.\r\n", nodes.Count(), displayedNodes.Count());
            }
            else
            {
                rsTextBox_Message.SetText("Split done. Found {0} result(s).\r\n", displayedNodes.Count());
            }

            rsTextBox_Message.SetAppendText(GetCreatedCode());
        }

        private void RunPerformanceMode(object arg)
        {
            rsTextBox_Message.SetText("Running...");

            Core.RegexPerformanceInfo regexPerformanceInfo = arg as Core.RegexPerformanceInfo;

            for (int i = 0; i < _performanceList.Rows.Count; i++)
            {
                Regex regex = _performanceList.Rows[i]["RegexObj"] as Regex;

                _performanceList.Rows[i]["ElapsedTime"] = GetElapsedTime(
                    () =>
                    {
                        for (int j = 0; j < _performanceRerunTimes; j++)
                        {
                            regex.Matches(regexPerformanceInfo.Content);
                        }
                    });
            }

            rsTextBox_Message.SetText("Performance done.\r\n");
        }

        private void StartRun()
        {
            Run(GetCurrentRunMode());
        }

        private void AbortRun()
        {
            if (_runThread != null)
            {
                switch (_runThread.ThreadState)
                {
                    case ThreadState.AbortRequested:
                        break;
                    case ThreadState.Aborted:
                        return;
                    case ThreadState.Background:
                        break;
                    case ThreadState.Running:
                        break;
                    case ThreadState.StopRequested:
                        break;
                    case ThreadState.Stopped:
                        return;
                    case ThreadState.SuspendRequested:
                        break;
                    case ThreadState.Suspended:
                        break;
                    case ThreadState.Unstarted:
                        return;
                    case ThreadState.WaitSleepJoin:
                        break;
                    default:
                        break;
                }

                rsTextBox_Message.SetText("Aborting...");
                _runThread.Abort();
                rsTextBox_Message.SetText("Aborted.");
            }
        }

        // events

        private void Form_Main_Load(object sender, EventArgs e)
        {

        }

        private void Form_Main_FormClosing(object sender, FormClosingEventArgs e)
        {
            AbortRun();
        }

        private void toolStripMenuItem_Execute_Run_Click(object sender, EventArgs e)
        {
            StartRun();
        }

        private void toolStripMenuItem_Execute_Abort_Click(object sender, EventArgs e)
        {
            AbortRun();
        }

        private void toolStripButton_Regex_Run_Click(object sender, EventArgs e)
        {
            StartRun();
        }

        private void toolStripButton_Regex_Abort_Click(object sender, EventArgs e)
        {
            AbortRun();
        }

        private void rsTreeView_Match_Group_AfterSelect(object sender, TreeViewEventArgs e)
        {
            Core.HighlightInfo hlInfo = (Core.HighlightInfo)e.Node.Tag;

            rsRichTextBox_Content.ClearAllHighlights();
            rsRichTextBox_Content.Highlight(hlInfo);
            rsRichTextBox_Content.ScrollToCaret();
        }

        private void rsTreeView_Match_Result_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Right)
            {
                HighlightInfo highlightInfo = e.Node.Tag as HighlightInfo;
                Clipboard.SetText(rsRichTextBox_Content.Text.Substring(highlightInfo.Index, highlightInfo.Length));
            }
        }

        private void toolStripMenuItem_File_Exit_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void toolStripMenuItem_Help_About_Click(object sender, EventArgs e)
        {
            Form_About form = new Form_About();
            form.ShowDialog();
        }

        private void toolStripButton_Performance_Use_Click(object sender, EventArgs e)
        {
            if (dataGridView_Performance_Main.SelectedCells.Count > 0)
            {
                int rowIndex = dataGridView_Performance_Main.SelectedCells[0].RowIndex;

                rsRichTextBox_Regex.Text = _performanceList.Rows[rowIndex]["Regex"].ToString();
                SetRegexOptions((RegexOptions)_performanceList.Rows[rowIndex]["Options"]);
            }
        }

        private void toolStripButton_Performance_Delete_Click(object sender, EventArgs e)
        {
            if (dataGridView_Performance_Main.SelectedCells.Count > 0)
            {
                int rowIndex = dataGridView_Performance_Main.SelectedCells[0].RowIndex;

                _performanceList.Rows.RemoveAt(rowIndex);
            }
        }

        private void toolStripComboBox_Performance_RerunTimes_TextChanged(object sender, EventArgs e)
        {
            int temp;

            if (int.TryParse(toolStripComboBox_Performance_RerunTimes.Text.Trim(), out temp))
            {
                _performanceRerunTimes = temp;
            }
            else
            {
                toolStripComboBox_Performance_RerunTimes.Text = _performanceRerunTimes.ToString();
            }
        }

        private void toolStripButton_Regex_AddToPerformanceList_Click(object sender, EventArgs e)
        {
            try
            {
                Regex regex = new Regex(rsRichTextBox_Regex.Text, GetRegexOptions());
                regex.Matches(rsRichTextBox_Content.Text);

                DataRow dr = _performanceList.NewRow();
                dr["Regex"] = rsRichTextBox_Regex.Text;
                dr["Options"] = GetRegexOptions();
                dr["ElapsedTime"] = DBNull.Value;
                dr["RegexObj"] = regex;

                _performanceList.Rows.Add(dr);

                rsTextBox_Message.SetText("Add to PerformanceList done.");
            }
            catch (Exception exception)
            {
                rsTextBox_Message.SetText("Add to PerformanceList failed.\r\nError:\r\n{0}", exception.Message);
            }
        }

        private void toolStripMenuItem_Snippets_Manage_Click(object sender, EventArgs e)
        {
            Form_CustomSnippets form = new Form_CustomSnippets();
            form.ShowDialog();

            LoadSnippets();
        }

        private void toolStripButton_Message_CopyCode_Click(object sender, EventArgs e)
        {
            if (GetCurrentRunMode() == RunMode.Performance)
            {
                MessageBox.Show("Copy Code isn't supported in Proformance Mode.");
            }
            else
            {
                if (!string.IsNullOrEmpty(_currentGenerateCode))
                    Clipboard.SetText(_currentGenerateCode);
            }
        }

        private void toolStripComboBox_Message_GenerateCode_SelectedIndexChanged(object sender, EventArgs e)
        {
            _currentGenerateCodeType = toolStripComboBox_Message_GenerateCodeType.SelectedItem as string;
        }

        private void tabControl_ModeTabs_SelectedIndexChanged(object sender, EventArgs e)
        {
            switch (GetCurrentRunMode())
            {
                case RunMode.Match:
                    toolStripStatusLabel_Mode.Text = "@ Match Mode";
                    toolStripStatusLabel_ModeDescription.Text = "In result tree, value in [] stands for Index, value in () stands for GroupName.";
                    break;
                case RunMode.Replace_Replacement:
                    toolStripStatusLabel_Mode.Text = "@ Replace.Replacement Mode";
                    toolStripStatusLabel_ModeDescription.Text = "All matches will be replaced by Replacement.";
                    break;
                case RunMode.Replace_MatchEvaluator:
                    toolStripStatusLabel_Mode.Text = "@ Replace.MatchEvaluator Mode";
                    toolStripStatusLabel_ModeDescription.Text = "All matches will be replaced by the user defined MatchEvaluator function.";
                    break;
                case RunMode.Split:
                    toolStripStatusLabel_Mode.Text = "@ Split Mode";
                    toolStripStatusLabel_ModeDescription.Text = "In result tree, value in [] stands for Index.";
                    break;
                case RunMode.Performance:
                    toolStripStatusLabel_Mode.Text = "@ Performance Mode";
                    toolStripStatusLabel_ModeDescription.Text = "This mode uses Regex.Matches(...) to test the regexes in the performance list.";
                    break;
            }
        }

        private void toolStripStatusLabel_GetUpdate_Click(object sender, EventArgs e)
        {
            WinAPI.API.ShellExecute(0, String.Empty, "http://code.google.com/p/regexsharp/downloads/list", String.Empty, String.Empty, 1);
        }

        private void toolStripMenuItem_File_OpenRSPROJFile_Click(object sender, EventArgs e)
        {
            if (openFileDialog_RSPROJ.ShowDialog() == DialogResult.OK)
            {
                OpenRSProjFile(openFileDialog_RSPROJ.FileName);
            }
        }

        private void toolStripMenuItem_File_SaveRSPROJFile_Click(object sender, EventArgs e)
        {
            if (saveFileDialog_RSPROJ.ShowDialog() == DialogResult.OK)
            {
                SaveRSProjFile(saveFileDialog_RSPROJ.FileName);
            }
        }

        private void OpenRSProjFile(string file)
        {
            Helper.Serializer<Config.RSProj> RSProjSerializer = new Helper.Serializer<Config.RSProj>();

            if (RSProjSerializer.CanDeserialize(file))
            {
                Config.RSProj rsproj = RSProjSerializer.Deserialize(file);

                this.rsRichTextBox_Content.Text = rsproj.Content;
                this.rsRichTextBox_Regex.Text = rsproj.Regex;
                SetRegexOptions(rsproj.RegexOptions);
                this.rsRichTextBox_Replace_Replacement.Text = rsproj.Replace_Replacement;
                this.rsRichTextBox_Replace_MatchEvaluator.Text = rsproj.Replace_MatchEvaluator;
                this.toolStripComboBox_Message_GenerateCodeType.SelectedIndex = rsproj.GenerateCodeTypeIndex;
                this.tabControl_Main.SelectedIndex = rsproj.MainTabIndex;
                this.tabControl_Replace.SelectedIndex = rsproj.ReplaceTabIndex;
                this.toolStripComboBox_Performance_RerunTimes.Text = rsproj.PerformanceRerunTimes.ToString();
                this._performanceList = rsproj.PerformanceList;
                dataGridView_Performance_Main.DataSource = _performanceList;
            }
            else
            {
                MessageBox.Show("Invalid RSProj File!");
            }
        }

        private void SaveRSProjFile(string file)
        {
            Helper.Serializer<Config.RSProj> RSProjSerializer = new Helper.Serializer<Config.RSProj>();

            Config.RSProj rsproj = new Config.RSProj();
            rsproj.Content = this.rsRichTextBox_Content.Text;
            rsproj.Regex = this.rsRichTextBox_Regex.Text;
            rsproj.RegexOptions = GetRegexOptions();
            rsproj.Replace_Replacement = this.rsRichTextBox_Replace_Replacement.Text;
            rsproj.Replace_MatchEvaluator = this.rsRichTextBox_Replace_MatchEvaluator.Text;
            rsproj.GenerateCodeTypeIndex = this.toolStripComboBox_Message_GenerateCodeType.SelectedIndex;
            rsproj.MainTabIndex = this.tabControl_Main.SelectedIndex;
            rsproj.ReplaceTabIndex = this.tabControl_Replace.SelectedIndex;
            rsproj.PerformanceRerunTimes = this._performanceRerunTimes;
            rsproj.PerformanceList = this._performanceList;

            RSProjSerializer.Serialize(rsproj, file);
        }
    }
}
